

	; Explosion control constants:
	; FADE_START  - Set to value between 0 and 1 to say when, during an explosion
	;               animation, the pieces should start to fade out. e.g. 1 to start
	;               immediately, .5 to start halfway through, 0 to never fade.
	; GRAVITY     - Per frame factor by which pieces gravitate towards the world.
	; XZ_DECAY    - Per frame factor by which pieces' world X and Z velocity decays.
	; JIGGLE_TRAJ - False to set exploding pieces on an exact trajectory defined by
	;               the vector from the blast focus to the centre of the tri.
	;               True to set exploding pieces on a trajectory based on the vector
	;               defined above, but with an added 'jiggle' factor. This adds a
	;               more realistic, chaotic appearance to the explosion and helps
	;               disguise the often uniform construction of meshes. However, this
	;               makes a call to start_mesh_explode() slower.
Const FADE_START# = 0.5
Const GRAVITY# = 0.001
Const XZ_DECAY# = 1.0 + GRAVITY		
Const JIGGLE_TRAJ% = True



Type tri_linkT
	Field prev.tri_linkT
	Field surf
	Field tri
	Field dx#,dy#,dz#
	Field pitch#,yaw#,roll#
End Type

Type explode_ctrlT
	Field tri_list.tri_linkT
	Field mesh
	Field life%
	Field fader#
	Field fade_start%
	Field exploding%
	Field o_pitch#
	Field o_yaw#
	Field o_roll#
End Type	



Global exp_ctrl.explode_ctrlT
Global exp_flash%
Global exp_stren%


;	; Scratch pad single tri mesh for doing rotations.
Global tm_mesh = 0
Global tm_surf = 0

;	; Scratch pad mesh used by copy_tri_explode() for subdivision.
Global sd_mesh = 0
Global sd_surf = 0
;HideEntity sd_mesh
;
;	; Scratch pad single vertex mesh used to 'jiggle' particle trajectory vectors.
Global vm_mesh = 0
Global vm_surf = 0
;
;	; Explosive sphere.
Global explosive = 0


Global explosive2 = 0
Global explosive3 = 0
Global exp_piv = 0	
Global exp_piv2 = 0	



Function TExplosion_Create( p_mesh, p_divs=3 )
	If explosive = 0 Then
		tm_mesh = CreateMesh()
		tm_surf = CreateSurface(tm_mesh)
		AddVertex(tm_surf,0,0,0)
		AddVertex(tm_surf,0,0,0)
		AddVertex(tm_surf,0,0,0)
		AddTriangle(tm_surf,0,1,2)
		HideEntity tm_mesh
		
		sd_mesh = CreateMesh()
		sd_surf = CreateSurface(sd_mesh)
		HideEntity sd_mesh
		
		vm_mesh = CreateMesh()
		vm_surf = CreateSurface(vm_mesh)
		AddVertex(vm_surf,0,0,0)
		HideEntity vm_mesh
		
		
		explosive = CreateSphere(6)
		
		ScaleMesh explosive,.15,.15,.15
		EntityRadius explosive,.15
		HideEntity explosive
		explosive2 = CopyMesh(explosive)
		explosive3 = CopyMesh(explosive)
		HideEntity explosive2
		HideEntity explosive3
		exp_piv = CreatePivot()	
		exp_piv2 = CreatePivot()	
		
	EndIf 
	
	Local shape_ctrl.explode_ctrlT=copy_mesh_explode(p_mesh,p_divs)
	PositionEntity shape_ctrl\mesh,EntityX(p_mesh),EntityY(p_mesh),EntityZ(p_mesh)
	EntityColor shape_ctrl\mesh,255,255,125
	
	ShowEntity explosive
	exp_ctrl = First explode_ctrlT
	PositionEntity explosive,EntityX(exp_ctrl\mesh),EntityY(exp_ctrl\mesh),EntityZ(exp_ctrl\mesh)
	
	exp_stren = 60
	
	Local ctrl.explode_ctrlT
	For ctrl.explode_ctrlT = Each explode_ctrlT
		start_mesh_explode(ctrl,(exp_stren*0.1),60)
		
		exp_ctrl = After exp_ctrl
		
		If exp_ctrl = Null
			HideEntity explosive
		Else
			PositionEntity explosive,EntityX(exp_ctrl\mesh),EntityY(exp_ctrl\mesh),EntityZ(exp_ctrl\mesh)
		EndIf
	Next
	
	flash_explosive()
	
	
End Function 



;
; Alternates colour of explosive spheres, to make them flash.
;
Function flash_explosive()
	
	exp_flash = exp_flash + 1
	
	If exp_flash = 4
		EntityColor explosive,0,0,255
		EntityColor explosive2,0,0,255
		EntityColor explosive3,0,0,255
	ElseIf exp_flash = 8
		EntityColor explosive,255,255,0
		EntityColor explosive2,255,255,0
		EntityColor explosive3,255,255,0
		exp_flash = 0
	EndIf
	
End Function




;
; Updates ALL explodable meshes that are currently exploding.
;
Function TExplosion_Update()
	Local this.explode_ctrlT = Null 
	For this.explode_ctrlT = Each explode_ctrlT
		
		If this\exploding
			
			If this\life
				tri.tri_linkT = this\tri_list
				
				If this\life <= this\fade_start
					EntityAlpha this\mesh,this\life * this\fader
				EndIf
				
				; Update all tris in linked list.
				While tri <> Null
					v0 = TriangleVertex(tri\surf,tri\tri,0)
					v1 = TriangleVertex(tri\surf,tri\tri,1)
					v2 = TriangleVertex(tri\surf,tri\tri,2)
					
					; Get 'centre of tri' vertex.
					cx# = VertexX(tri\surf,v2+1)
					cy# = VertexY(tri\surf,v2+1)
					cz# = VertexZ(tri\surf,v2+1)
					
					; Load scratch pad tri mesh.
					VertexCoords tm_surf,0,VertexX(tri\surf,v0)-cx,VertexY(tri\surf,v0)-cy,VertexZ(tri\surf,v0)-cz
					VertexCoords tm_surf,1,VertexX(tri\surf,v1)-cx,VertexY(tri\surf,v1)-cy,VertexZ(tri\surf,v1)-cz
					VertexCoords tm_surf,2,VertexX(tri\surf,v2)-cx,VertexY(tri\surf,v2)-cy,VertexZ(tri\surf,v2)-cz
					VertexNormal tm_surf,0,VertexNX(tri\surf,v0),VertexNY(tri\surf,v0),VertexNZ(tri\surf,v0)
					VertexNormal tm_surf,1,VertexNX(tri\surf,v1),VertexNY(tri\surf,v1),VertexNZ(tri\surf,v1)
					VertexNormal tm_surf,2,VertexNX(tri\surf,v2),VertexNY(tri\surf,v2),VertexNZ(tri\surf,v2)
					
					; Do rotations.
					RotateMesh tm_mesh,tri\pitch,tri\yaw,tri\roll
					
					; Copy back to mesh tri adding translation.
					VertexCoords tri\surf,v0,VertexX(tm_surf,0)+cx+tri\dx,VertexY(tm_surf,0)+cy+tri\dy,VertexZ(tm_surf,0)+cz+tri\dz
					VertexCoords tri\surf,v1,VertexX(tm_surf,1)+cx+tri\dx,VertexY(tm_surf,1)+cy+tri\dy,VertexZ(tm_surf,1)+cz+tri\dz
					VertexCoords tri\surf,v2,VertexX(tm_surf,2)+cx+tri\dx,VertexY(tm_surf,2)+cy+tri\dy,VertexZ(tm_surf,2)+cz+tri\dz
					VertexNormal tri\surf,v0,VertexNX(tm_surf,0),VertexNY(tm_surf,0),VertexNZ(tm_surf,0)
					VertexNormal tri\surf,v1,VertexNX(tm_surf,1),VertexNY(tm_surf,1),VertexNZ(tm_surf,1)
					VertexNormal tri\surf,v2,VertexNX(tm_surf,2),VertexNY(tm_surf,2),VertexNZ(tm_surf,2)
					
					VertexCoords tri\surf,v2+1,cx+tri\dx,cy+tri\dy,cz+tri\dz
					
					; Update gravity effect, ready for next update.
					tri\dy = tri\dy-GRAVITY
					tri\dx = tri\dx/XZ_DECAY
					tri\dz = tri\dz/XZ_DECAY
					
					tri = tri\prev
				Wend
				
				this\life = this\life - 1
			Else
				; Mesh has finished exploding.
				free_mesh_explode(this)
			EndIf
			
		EndIf
		
	Next
	
End Function


;
; Creates a subdivided (optional), unwelded copy of an existing mesh.
; Explode info for all tris in the new mesh are kept in a separate linked list
; contained in the control variable returned to the caller.
; Note: the source mesh being copied remains completely unaltered.
;
; Params:
; s_mesh     - Source mesh to be copied.
; divs       - Number of times to perform x4 subdivision on each source tri.
; keep_surfs - True to keep the same amount of surfaces in
;              the copy as in the source mesh.
;              False (Default) to copy all tris in the source mesh
;              to a single surface in the copy.
;
; Returns:
; Pointer to the control variable (of type explode_ctrlT) for the
; new explodable mesh created.
;
Function copy_mesh_explode.explode_ctrlT(s_mesh,divs=0,keep_surfs%=False)
	
	Local tri_list.tri_linkT = Null
	
	Local d_mesh = CreateMesh()
	
	For sno = 1 To CountSurfaces(s_mesh)
		
		s_surf = GetSurface(s_mesh,sno)
		nt = CountTriangles(s_surf)
		
		If sno = 1 Or keep_surfs Then d_surf = CreateSurface(d_mesh)
		
		For tno = 0 To nt-1
			tri_list = copy_tri_explode(s_surf,tno,d_surf,divs,tri_list)
		Next
		
	Next
	
	; Create and return this explodable mesh's control variable.
	Local ctrl.explode_ctrlT = New explode_ctrlT
	ctrl\tri_list = tri_list
	ctrl\mesh = d_mesh
	ctrl\exploding = False
	
	Return ctrl
	
End Function


;
; Adds an unwelded copy of a tri from the source surface to the destination
; surface, performing any subdivision requested.
;
; Subdivision is done by calling this function recursively, splitting the
; source tri into 4 unwelded tris each time, like so:
;
;           v1
;           /\ 
;         /____\
;       /  \  /  \
;     /_____\/_____\
;    v0            v2
;
; Params:
; s_surf   - Source surface containing tri to be copied.
; tri      - Index of tri to be copied.
; d_surf   - Destination surface to copy the source tri to.
; divs     - Number of times to perform x4 subdivision on the source tri.
; tri_list - Current top item in the linked list.
; reset    - True (default) to clear scratch pad mesh.
;            False to not clear scratch pad mesh (used internally only!).
;
; Returns:
; The current top item in the linked list.
;
Function copy_tri_explode.tri_linkT(s_surf,tri,d_surf,divs,tri_list.tri_linkT,reset%=True)
	
	If reset Then ClearSurface(sd_surf)
	
	Local sv0 = TriangleVertex(s_surf,tri,0)
	Local sv1 = TriangleVertex(s_surf,tri,1)
	Local sv2 = TriangleVertex(s_surf,tri,2)
	
	; Get coords of all 3 vertices of source tri.
	Local x0# = VertexX(s_surf,sv0)
	Local y0# = VertexY(s_surf,sv0)
	Local z0# = VertexZ(s_surf,sv0)
	Local x1# = VertexX(s_surf,sv1)
	Local y1# = VertexY(s_surf,sv1)
	Local z1# = VertexZ(s_surf,sv1)
	Local x2# = VertexX(s_surf,sv2)
	Local y2# = VertexY(s_surf,sv2)
	Local z2# = VertexZ(s_surf,sv2)
	
	; Get normals of all 3 vertices of source tri.
	Local nx0# = VertexNX(s_surf,sv0)
	Local ny0# = VertexNY(s_surf,sv0)
	Local nz0# = VertexNZ(s_surf,sv0)
	Local nx1# = VertexNX(s_surf,sv1)
	Local ny1# = VertexNY(s_surf,sv1)
	Local nz1# = VertexNZ(s_surf,sv1)
	Local nx2# = VertexNX(s_surf,sv2)
	Local ny2# = VertexNY(s_surf,sv2)
	Local nz2# = VertexNZ(s_surf,sv2)
	
	; Get tex coords of all 3 vertices of source tri.
	Local u0# = VertexU(s_surf,sv0)
	Local v0# = VertexV(s_surf,sv0)
	Local w0# = VertexW(s_surf,sv0)
	Local u1# = VertexU(s_surf,sv1)
	Local v1# = VertexV(s_surf,sv1)
	Local w1# = VertexW(s_surf,sv1)
	Local u2# = VertexU(s_surf,sv2)
	Local v2# = VertexV(s_surf,sv2)
	Local w2# = VertexW(s_surf,sv2)
	
	; Get colour of all 3 vertices of source tri.
	Local r0# = VertexRed(s_surf,sv0)
	Local g0# = VertexGreen(s_surf,sv0)
	Local b0# = VertexBlue(s_surf,sv0)
	Local r1# = VertexRed(s_surf,sv1)
	Local g1# = VertexGreen(s_surf,sv1)
	Local b1# = VertexBlue(s_surf,sv1)
	Local r2# = VertexRed(s_surf,sv2)
	Local g2# = VertexGreen(s_surf,sv2)
	Local b2# = VertexBlue(s_surf,sv2)
	
	If divs
		; Calculate coords of the 3 discrete vertices used by subdivision.
		x3# = (x1+x0)/2.0
		y3# = (y1+y0)/2.0
		z3# = (z1+z0)/2.0
		x4# = (x2+x1)/2.0
		y4# = (y2+y1)/2.0
		z4# = (z2+z1)/2.0
		x5# = (x0+x2)/2.0
		y5# = (y0+y2)/2.0
		z5# = (z0+z2)/2.0
		
		; Calculate normals of the 3 discrete vertices used by subdivision.
		nx3# = (nx1+nx0)/2.0
		ny3# = (ny1+ny0)/2.0
		nz3# = (nz1+nz0)/2.0
		nx4# = (nx2+nx1)/2.0
		ny4# = (ny2+ny1)/2.0
		nz4# = (nz2+nz1)/2.0
		nx5# = (nx0+nx2)/2.0
		ny5# = (ny0+ny2)/2.0
		nz5# = (nz0+nz2)/2.0
		
		; Unify.
		nl# = Sqr(nx3*nx3 + ny3*ny3 + nz3*nz3)
		nx3 = nx3 / nl#
		ny3 = ny3 / nl#
		nz3 = nz3 / nl#
		nl# = Sqr(nx4*nx4 + ny4*ny4 + nz4*nz4)
		nx4 = nx4 / nl#
		ny4 = ny4 / nl#
		nz4 = nz4 / nl#
		nl# = Sqr(nx5*nx5 + ny5*ny5 + nz5*nz5)
		nx5 = nx5 / nl#
		ny5 = ny5 / nl#
		nz5 = nz5 / nl#
		
		; Calculate tex coords of the 3 discrete vertices used by subdivision.
		u3# = (u1+u0)/2.0
		v3# = (v1+v0)/2.0
		w3# = (w1+w0)/2.0
		u4# = (u2+u1)/2.0
		v4# = (v2+v1)/2.0
		w4# = (w2+w1)/2.0
		u5# = (u0+u2)/2.0
		v5# = (v0+v2)/2.0
		w5# = (w0+w2)/2.0
		
		; Calculate colour of the 3 discrete vertices used by subdivision.
		r3# = (r1+r0)/2.0
		g3# = (g1+g0)/2.0
		b3# = (b1+b0)/2.0
		r4# = (r2+r1)/2.0
		g4# = (g2+g1)/2.0
		b4# = (b2+b1)/2.0
		r5# = (r0+r2)/2.0
		g5# = (g0+g2)/2.0
		b5# = (b0+b2)/2.0
		
		; Add the 4 unwelded tris comprising the subdivision to the
		; temporary, scratch pad mesh surface.
		tv0 = AddVertex(sd_surf,x0,y0,z0)
		tv3 = AddVertex(sd_surf,x3,y3,z3)
		tv5 = AddVertex(sd_surf,x5,y5,z5)
		tri0 = AddTriangle(sd_surf,tv0,tv3,tv5)
		VertexNormal sd_surf,tv0,nx0,ny0,nz0
		VertexNormal sd_surf,tv3,nx3,ny3,nz3
		VertexNormal sd_surf,tv5,nx5,ny5,nz5
		VertexColor sd_surf,tv0,r0,g0,b0
		VertexColor sd_surf,tv3,r3,g3,b3
		VertexColor sd_surf,tv5,r5,g5,b5
		VertexTexCoords sd_surf,tv0,u0,v0,w0
		VertexTexCoords sd_surf,tv3,u3,v3,w3
		VertexTexCoords sd_surf,tv5,u5,v5,w5
		
		tv1 = AddVertex(sd_surf,x1,y1,z1)
		tv4 = AddVertex(sd_surf,x4,y4,z4)
		tv3b = AddVertex(sd_surf,x3,y3,z3)
		tri1 = AddTriangle(sd_surf,tv1,tv4,tv3b)
		VertexNormal sd_surf,tv1,nx1,ny1,nz1
		VertexNormal sd_surf,tv4,nx4,ny4,nz4
		VertexNormal sd_surf,tv3b,nx3,ny3,nz3
		VertexColor sd_surf,tv1,r1,g1,b1
		VertexColor sd_surf,tv4,r4,g4,b4
		VertexColor sd_surf,tv3b,r3,g3,b3
		VertexTexCoords sd_surf,tv1,u1,v1,w1
		VertexTexCoords sd_surf,tv4,u4,v4,w4
		VertexTexCoords sd_surf,tv3b,u3,v3,w3
		
		tv2 = AddVertex(sd_surf,x2,y2,z2)
		tv5b = AddVertex(sd_surf,x5,y5,z5)
		tv4b = AddVertex(sd_surf,x4,y4,z4)
		tri2 = AddTriangle(sd_surf,tv2,tv5b,tv4b)
		VertexNormal sd_surf,tv2,nx2,ny2,nz2
		VertexNormal sd_surf,tv5b,nx5,ny5,nz5
		VertexNormal sd_surf,tv4b,nx4,ny4,nz4
		VertexColor sd_surf,tv2,r2,g2,b2
		VertexColor sd_surf,tv5b,r5,g5,b5
		VertexColor sd_surf,tv4b,r4,g4,b4
		VertexTexCoords sd_surf,tv2,u2,v2,w2
		VertexTexCoords sd_surf,tv5b,u5,v5,w5
		VertexTexCoords sd_surf,tv4b,u4,v4,w4
		
		tv3c = AddVertex(sd_surf,x3,y3,z3)
		tv4c = AddVertex(sd_surf,x4,y4,z4)
		tv5c = AddVertex(sd_surf,x5,y5,z5)
		tri3 = AddTriangle(sd_surf,tv3c,tv4c,tv5c)
		VertexNormal sd_surf,tv3c,nx3,ny3,nz3
		VertexNormal sd_surf,tv4c,nx4,ny4,nz4
		VertexNormal sd_surf,tv5c,nx5,ny5,nz5
		VertexColor sd_surf,tv3c,r3,g3,b3
		VertexColor sd_surf,tv4c,r4,g4,b4
		VertexColor sd_surf,tv5c,r5,g5,b5
		VertexTexCoords sd_surf,tv3c,u3,v3,w3
		VertexTexCoords sd_surf,tv4c,u4,v4,w4
		VertexTexCoords sd_surf,tv5c,u5,v5,w5
		
		divs = divs - 1
		
		tri_list = copy_tri_explode(sd_surf,tri0,d_surf,divs,tri_list,False)
		tri_list = copy_tri_explode(sd_surf,tri1,d_surf,divs,tri_list,False)
		tri_list = copy_tri_explode(sd_surf,tri2,d_surf,divs,tri_list,False)
		tri_list = copy_tri_explode(sd_surf,tri3,d_surf,divs,tri_list,False)
		
	Else
		
		dv0 = AddVertex(d_surf,x0,y0,z0)
		dv1 = AddVertex(d_surf,x1,y1,z1)
		dv2 = AddVertex(d_surf,x2,y2,z2)
		
		; Calculate and add a lone 'centre of tri' vertex (needed for
		; per-tri rotations and blast trajectory calculation).
		tx# = (x2+x1)/2.0
		ty# = (y2+y1)/2.0
		tz# = (z2+z1)/2.0
		cvx# = tx - ((tx-x0)/3.0)
		cvy# = ty - ((ty-y0)/3.0)
		cvz# = tz - ((tz-z0)/3.0)
		AddVertex(d_surf,cvx,cvy,cvz)
		
		real_tri = AddTriangle(d_surf,dv0,dv1,dv2)
		
		VertexNormal d_surf,dv0,nx0,ny0,nz0
		VertexNormal d_surf,dv1,nx1,ny1,nz1
		VertexNormal d_surf,dv2,nx2,ny2,nz2
		VertexColor d_surf,dv0,r0,g0,b0
		VertexColor d_surf,dv1,r1,g1,b1
		VertexColor d_surf,dv2,r2,g2,b2
		VertexTexCoords d_surf,dv0,u0,v0,w0
		VertexTexCoords d_surf,dv1,u1,v1,w1
		VertexTexCoords d_surf,dv2,u2,v2,w2
		
		; Add this tri to the linked list.
		link.tri_linkT = New tri_linkT
		link\prev = tri_list
		link\surf = d_surf
		link\tri = real_tri
		
		tri_list = link	
	EndIf
	
	Return tri_list
	
End Function


;
; Initializes and authorizes a mesh to start exploding.
; Note: can handle starting an explosion on a mesh that's already exploding.
;
; Params:
; ctrl        - Control variable of the mesh to start exploding.
; blast       - Strength of the blast to explode the mesh with.
; life        - Duration of the explosion animation (in frames).
; bfx,bfy,bfz - Blast focus coords (point in 3D space where the explosion is to
;               occur), relative to mesh centre.
; loc         - True to set blast focus using local space coords.
;               False (default) to set blast focus using coords aligned to world
;               axes. e.g. a blast focus of 0,-1,0 will cause an explosion directly
;               below the mesh's centre, regardless of the mesh's current rotation.
;
Function start_mesh_explode(ctrl.explode_ctrlT,blast#=1,life%=100,bfx#=0,bfy#=0,bfz#=0,loc%=False)
	
	If loc
		If ctrl\exploding
			; Temporarily re-instate mesh's original rotation so we can
			; calculate local blast focus coords.
			RotateEntity ctrl\mesh,ctrl\o_pitch,ctrl\o_yaw,ctrl\o_roll,1
			
			; Convert blast focus to world-aligned coords.	
			TFormPoint bfx,bfy,bfz,ctrl\mesh,0
			bfx = TFormedX() - EntityX(ctrl\mesh,1)
			bfy = TFormedY() - EntityY(ctrl\mesh,1)
			bfz = TFormedZ() - EntityZ(ctrl\mesh,1)
			
			RotateEntity ctrl\mesh,0,0,0,1
		Else
			; Convert blast focus to world-aligned coords.	
			TFormPoint bfx,bfy,bfz,ctrl\mesh,0
			bfx = TFormedX() - EntityX(ctrl\mesh,1)
			bfy = TFormedY() - EntityY(ctrl\mesh,1)
			bfz = TFormedZ() - EntityZ(ctrl\mesh,1)
		EndIf
	EndIf
	
	If Not ctrl\exploding
		; Align mesh axes to world axes, keeping mesh's visible
		; orientation (needed for gravity to work).
		ctrl\o_pitch = EntityPitch(ctrl\mesh,1)
		ctrl\o_yaw = EntityYaw(ctrl\mesh,1)
		ctrl\o_roll = EntityRoll(ctrl\mesh,1)
		RotateEntity ctrl\mesh,0,0,0,1
		RotateMesh ctrl\mesh,ctrl\o_pitch,ctrl\o_yaw,ctrl\o_roll
	EndIf
	
	tri.tri_linkT = ctrl\tri_list
	
	If JIGGLE_TRAJ
		While tri <> Null
			
			; Get 'centre of tri' vertex.
			cv = TriangleVertex(tri\surf,tri\tri,2) + 1
			cvx# = VertexX(tri\surf,cv)
			cvy# = VertexY(tri\surf,cv)
			cvz# = VertexZ(tri\surf,cv)
			
			; Use the vector from bfx,bfy,bfz (blast focus) to cvx,cvy,cvz ('centre
			; of tri' vert) as the trajectory, adding a random 'jiggle' factor.
			VertexCoords vm_surf,0,cvx-bfx,cvy-bfy,cvz-bfz
			RotateMesh vm_mesh,Rnd(-10,10),Rnd(-10,10),Rnd(-10,10)
			
			tvx# = VertexX(vm_surf,0)
			tvy# = VertexY(vm_surf,0)
			tvz# = VertexZ(vm_surf,0)
			tvl# = Sqr(tvx*tvx + tvy*tvy + tvz*tvz)
			
			; Set velocity along trajectory vector based on proximity to
			; explosion (blast focus), explosion strength and a random factor.
			v_scale# = tvl * Rnd(20.0,50.0)
			
			; Add to current dx,dy,dz in case this mesh is already exploding!
			tri\dx = tri\dx + (((tvx/tvl)/v_scale) * blast)
			tri\dy = tri\dy + (((tvy/tvl)/v_scale) * blast)
			tri\dz = tri\dz + (((tvz/tvl)/v_scale) * blast)
			
			; Base rotation on velocity.
			rot# = (Abs(tri\dx) + Abs(tri\dy) + Abs(tri\dz)) * 100
			tri\pitch = Rnd(-rot,rot)
			tri\yaw = Rnd(-rot,rot)
			tri\roll = Rnd(-rot,rot)
			
			tri = tri\prev
		Wend
	Else
		While tri <> Null
			
			; Get 'centre of tri' vertex.
			cv = TriangleVertex(tri\surf,tri\tri,2) + 1
			cvx# = VertexX(tri\surf,cv)
			cvy# = VertexY(tri\surf,cv)
			cvz# = VertexZ(tri\surf,cv)
			
			; Use the vector from bfx,bfy,bfz (blast focus) to cvx,cvy,cvz
			; ('centre of tri' vert) as the trajectory.
			tvx# = cvx - bfx
			tvy# = cvy - bfy
			tvz# = cvz - bfz
			tvl# = Sqr(tvx*tvx + tvy*tvy + tvz*tvz)
			
			; Set velocity along trajectory vector based on proximity to
			; explosion (blast focus), explosion strength and a random factor.
			v_scale# = tvl * Rnd(20.0,50.0)
			
			; Add to current dx,dy,dz in case this mesh is already exploding!
			tri\dx = tri\dx + (((tvx/tvl)/v_scale) * blast)
			tri\dy = tri\dy + (((tvy/tvl)/v_scale) * blast)
			tri\dz = tri\dz + (((tvz/tvl)/v_scale) * blast)
			
			; Base rotation on velocity.
			rot# = (Abs(tri\dx) + Abs(tri\dy) + Abs(tri\dz)) * 100
			tri\pitch = Rnd(-rot,rot)
			tri\yaw = Rnd(-rot,rot)
			tri\roll = Rnd(-rot,rot)
			
			tri = tri\prev
		Wend
	EndIf
	
	ctrl\life = life
	ctrl\fade_start = Ceil(Float(life)*FADE_START#)
	ctrl\fader = 1.0/(ctrl\fade_start+1)
	ctrl\exploding = True
	
	EntityFX ctrl\mesh,16
	
End Function


;
; Free all mem used by an explodable mesh created with copy_mesh_explode().
;
; Params:
; ctrl - Control variable of the explodable mesh to be freed.
;
Function free_mesh_explode(ctrl.explode_ctrlT)
	
	this.tri_linkT = ctrl\tri_list
	
	While this <> Null
		delme.tri_linkT = this
		this = delme\prev
		Delete delme
	Wend
	
	FreeEntity ctrl\mesh
	Delete ctrl
	
End Function

;~IDEal Editor Parameters:
;~B#49
;~C#Blitz3D